package com.ikas.ai.server.module.instance.service;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikas.ai.server.module.instance.dorisDao.DorisWorkInstanceStepDetailCostDao;
import com.ikas.ai.server.module.instance.dorisDao.DorisWorkInstanceStepDetailDao;
import com.ikas.ai.server.module.instance.model.DorisWorkInstanceStepDetail;
import com.ikas.ai.server.module.instance.model.DorisWorkInstanceStepDetailCost;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

@Service
@Slf4j
public class DorisWorkInstanceStepDetailCostService extends ServiceImpl<DorisWorkInstanceStepDetailCostDao, DorisWorkInstanceStepDetailCost> {

    @Autowired
    DorisWorkInstanceStepService dorisWorkInstanceStepService;
    @Autowired
    DorisWorkFlowInstanceService dorisWorkFlowInstanceService;
    @Autowired
    DorisWorkInstanceStepDetailDao dorisWorkInstanceStepDetailDao;


    @Value("${work-instance.step-detail.cost-time.max-length:100}")
    Integer maxStepDetailCostTimeLength;

    /**
     * @param machineNo
     * @param detail
     */
    @Transactional(rollbackFor = Exception.class)
    public void computeAvgCostTime(String machineNo, DorisWorkInstanceStepDetail detail) {
        if (machineNo == null) {
            return;
        }
        DorisWorkInstanceStepDetailCost one = getOne(
                new LambdaQueryWrapper<DorisWorkInstanceStepDetailCost>()
                        .eq(DorisWorkInstanceStepDetailCost::getMachineNo, machineNo)
                        .eq(DorisWorkInstanceStepDetailCost::getWfName, detail.getWfName())
                        .eq(DorisWorkInstanceStepDetailCost::getStepName, detail.getStepName())
                        .eq(DorisWorkInstanceStepDetailCost::getMeteCode, detail.getMeteCode())
        );
        /**
         * 如果为空，新建一个对象，并新建一个数组并放入当前delay时间
         */
        if (one == null) {
            synchronized (this) {
                one = getOne(
                        new LambdaQueryWrapper<DorisWorkInstanceStepDetailCost>()
                                .eq(DorisWorkInstanceStepDetailCost::getMachineNo, machineNo)
                                .eq(DorisWorkInstanceStepDetailCost::getWfName, detail.getWfName())
                                .eq(DorisWorkInstanceStepDetailCost::getStepName, detail.getStepName())
                                .eq(DorisWorkInstanceStepDetailCost::getMeteCode, detail.getMeteCode())
                );
                if (one == null) {
                    one = new DorisWorkInstanceStepDetailCost().setMachineNo(machineNo).setWfName(detail.getWfName()).setStepName(detail.getStepName()).setMeteCode(detail.getMeteCode());
                    List<Long> costTimeArray = new ArrayList<>();
                    costTimeArray.add(detail.getCostTime());
                    one.setCostTimeArray(costTimeArray);
                    one.setAvgCostTime(detail.getCostTime());
                    save(one);
                } else {
                    one = dealWithCostTime(detail.getCostTime(), one);
                    one.setUpdateTime(new Date());
                    save(one);
                }
            }
        } else {
            one = dealWithCostTime(detail.getCostTime(), one);
            one.setUpdateTime(new Date());
            save(one);
        }
        DorisWorkInstanceStepDetail dorisWorkInstanceStepDetail = new DorisWorkInstanceStepDetail();
        dorisWorkInstanceStepDetail.setId(detail.getId());
        dorisWorkInstanceStepDetail.setAvgCostTime(one.getAvgCostTime());
        dorisWorkInstanceStepDetail.setUpdateTime(one.getUpdateTime());
        dorisWorkInstanceStepDetailDao.updateById(dorisWorkInstanceStepDetail);
        log.info("执行doris计算平均时长");
    }


    private DorisWorkInstanceStepDetailCost dealWithCostTime(Long delay, DorisWorkInstanceStepDetailCost one) {
        if (delay == null) {
            return one;
        }
        if (one.getCostTimeArray() == null) {
            one.setCostTimeArray(new ArrayList<>());
        }
        LinkedList<Long> costTimeArray = new LinkedList<>(one.getCostTimeArray());
        if (costTimeArray.size() < maxStepDetailCostTimeLength) {
            //DO NOTHING
            costTimeArray.addFirst(delay);
        } else if (costTimeArray.size() > maxStepDetailCostTimeLength) {
            Integer defaultSize = costTimeArray.size();
            for (int k = 0; k <= defaultSize - maxStepDetailCostTimeLength; k++) {
                costTimeArray.pollLast();
            }
            costTimeArray.addFirst(delay);
        } else {
            costTimeArray.removeLast();
            costTimeArray.addFirst(delay);
        }
        one.setCostTimeArray(costTimeArray);
        Long sum = 0L;
        for (Long costTimeElement : costTimeArray) {
            sum += costTimeElement;
        }
        Long avgCostTime = 0L;
        if (sum != 0L) {
            avgCostTime = sum / costTimeArray.size();
        }
        one.setAvgCostTime(avgCostTime);
        return one;
    }
}
